//
// DotNetNuke - http://www.dotnetnuke.com
// Copyright (c) 2002-2010
// by Perpetual Motion Interactive Systems Inc. ( http://www.perpetualmotion.ca )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Host;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Services.Localization;
using DotNetNuke.Entities.Portals;
namespace DotNetNuke.Services.Cache
{
	public abstract class CachingProvider
	{
		private static System.Web.Caching.Cache _objCache;
		private static string _cachePrefix = "DNN_";
		protected static System.Web.Caching.Cache Cache {
			get {
				if (_objCache == null) {
					_objCache = HttpRuntime.Cache;
				}
				return _objCache;
			}
		}
		
		public static string CleanCacheKey(string CacheKey)
		{
            if( String.IsNullOrEmpty(CacheKey))
			{
                throw new ArgumentException("Argument cannot be null or an empty string", "CacheKey");
            }
			return CacheKey.Substring(_cachePrefix.Length);
        }
		public static string GetCacheKey(string CacheKey)
		{
			if (string.IsNullOrEmpty(CacheKey)) {
				throw new ArgumentException("Argument cannot be null or an empty string", "CacheKey");
			}
			return _cachePrefix + CacheKey;
		}
		public static CachingProvider Instance()
		{
			return DotNetNuke.ComponentModel.ComponentFactory.GetComponent<CachingProvider>();
		}
		private void ClearCacheInternal(string prefix, bool clearRuntime)
		{
			foreach (DictionaryEntry objDictionaryEntry in HttpRuntime.Cache) {
				if (Convert.ToString(objDictionaryEntry.Key).StartsWith(prefix)) {
					if (clearRuntime) {
						RemoveInternal(Convert.ToString(objDictionaryEntry.Key));
					} else {
						Remove(Convert.ToString(objDictionaryEntry.Key));
					}
				}
			}
		}
		private void ClearCacheKeysByPortalInternal(int portalId, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.PortalCacheKey, clearRuntime, Null.NullInteger, String.Empty);
			RemoveFormattedCacheKey(DataCache.LocalesCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.ProfileDefinitionsCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.ListsCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.SkinsCacheKey, clearRuntime, portalId);
		}
		private void ClearDesktopModuleCacheInternal(int portalId, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.DesktopModuleCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.PortalDesktopModuleCacheKey, clearRuntime, portalId);
			RemoveCacheKey(DataCache.ModuleDefinitionCacheKey, clearRuntime);
			RemoveCacheKey(DataCache.ModuleControlsCacheKey, clearRuntime);
		}
		private void ClearFolderCacheInternal(int portalId, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.FolderCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.FolderPermissionCacheKey, clearRuntime, portalId);
		}
		private void ClearHostCacheInternal(bool clearRuntime)
		{
			RemoveCacheKey(DataCache.HostSettingsCacheKey, clearRuntime);
			RemoveCacheKey(DataCache.SecureHostSettingsCacheKey, clearRuntime);
			RemoveCacheKey(DataCache.PortalAliasCacheKey, clearRuntime);
			RemoveCacheKey("CSS", clearRuntime);
			RemoveCacheKey(DataCache.DesktopModulePermissionCacheKey, clearRuntime);
			RemoveCacheKey("GetRoles", clearRuntime);
			RemoveCacheKey("CompressionConfig", clearRuntime);
			ClearFolderCacheInternal(-1, clearRuntime);
			ClearDesktopModuleCacheInternal(-1, clearRuntime);
			ClearCacheKeysByPortalInternal(-1, clearRuntime);
		}
		private void ClearModuleCacheInternal(int tabId, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.TabModuleCacheKey, clearRuntime, tabId);
			RemoveFormattedCacheKey(DataCache.ModulePermissionCacheKey, clearRuntime, tabId);
		}
		private void ClearModulePermissionsCachesByPortalInternal(int portalId, bool clearRuntime)
		{
			TabController objTabs = new TabController();
			foreach (KeyValuePair<int, DotNetNuke.Entities.Tabs.TabInfo> tabPair in objTabs.GetTabsByPortal(portalId)) {
				RemoveFormattedCacheKey(DataCache.ModulePermissionCacheKey, clearRuntime, tabPair.Value.TabID);
			}
		}
		private void ClearPortalCacheInternal(int portalId, bool cascade, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.PortalSettingsCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.PortalUserCountCacheKey, clearRuntime, portalId);

            Dictionary<string, Locale> locales = LocaleController.Instance.GetLocales(portalId);
            if (locales == null || locales.Count == 0)
			{
                //At least attempt to remove default locale
                string defaultLocale = PortalController.GetPortalDefaultLanguage(portalId);
                RemoveCacheKey(String.Format(DataCache.PortalCacheKey, portalId.ToString(), defaultLocale), clearRuntime);
            }
			else
			{
                foreach (Locale portalLocale in LocaleController.Instance.GetLocales(portalId).Values)
				{
					RemoveCacheKey(String.Format(DataCache.PortalCacheKey, portalId.ToString(), portalLocale.Code), clearRuntime);
                }
            }
			if (cascade) {
				TabController objTabs = new TabController();
				foreach (KeyValuePair<int, DotNetNuke.Entities.Tabs.TabInfo> tabPair in objTabs.GetTabsByPortal(portalId)) {
					ClearModuleCacheInternal(tabPair.Value.TabID, clearRuntime);
				}
				DotNetNuke.Entities.Modules.ModuleController moduleController = new DotNetNuke.Entities.Modules.ModuleController();
				foreach (DotNetNuke.Entities.Modules.ModuleInfo moduleInfo in moduleController.GetModules(portalId)) {
					RemoveCacheKey("GetModuleSettings" + moduleInfo.ModuleID.ToString(), clearRuntime);
				}
			}
			ClearFolderCacheInternal(portalId, clearRuntime);
			ClearCacheKeysByPortalInternal(portalId, clearRuntime);
			ClearDesktopModuleCacheInternal(portalId, clearRuntime);
			ClearTabCacheInternal(portalId, clearRuntime);
		}
		private void ClearTabCacheInternal(int portalId, bool clearRuntime)
		{
			RemoveFormattedCacheKey(DataCache.TabCacheKey, clearRuntime, portalId);
			RemoveFormattedCacheKey(DataCache.TabPermissionCacheKey, clearRuntime, portalId);
            Dictionary<string, Locale> locales = LocaleController.Instance.GetLocales(portalId);
            if (locales == null || locales.Count == 0)
            {
                //At least attempt to remove default locale
                string defaultLocale = PortalController.GetPortalDefaultLanguage(portalId);
                RemoveCacheKey(string.Format(DataCache.TabPathCacheKey, defaultLocale, portalId.ToString()), clearRuntime);
            }
            else
            {
                foreach (Locale portalLocale in LocaleController.Instance.GetLocales(portalId).Values)
                {
                    RemoveCacheKey(string.Format(DataCache.TabPathCacheKey, portalLocale.Code, portalId.ToString()), clearRuntime);
                }
            }

            RemoveCacheKey(string.Format(DataCache.TabPathCacheKey, Null.NullString, portalId.ToString()), clearRuntime);

		}
		private void RemoveCacheKey(string CacheKey, bool clearRuntime)
		{
			if (clearRuntime) {
				RemoveInternal(GetCacheKey(CacheKey));
			} else {
				Remove(GetCacheKey(CacheKey));
			}
		}
		private void RemoveFormattedCacheKey(string CacheKeyBase, bool clearRuntime, params object[] parameters)
		{
			if (clearRuntime) {
				RemoveInternal(string.Format(GetCacheKey(CacheKeyBase), parameters));
			} else {
				Remove(string.Format(GetCacheKey(CacheKeyBase), parameters));
			}
		}
		protected void ClearCacheInternal(string cacheType, string data, bool clearRuntime)
		{
			switch (cacheType) {
				case "Prefix":
					ClearCacheInternal(data, clearRuntime);
					break;
				case "Host":
					ClearHostCacheInternal(clearRuntime);
					break;
				case "Folder":
					ClearFolderCacheInternal(int.Parse(data), clearRuntime);
					break;
				case "Module":
					ClearModuleCacheInternal(int.Parse(data), clearRuntime);
					break;
				case "ModulePermissionsByPortal":
					ClearModulePermissionsCachesByPortalInternal(int.Parse(data), clearRuntime);
					break;
				case "Portal":
					ClearPortalCacheInternal(int.Parse(data), false, clearRuntime);
					break;
				case "PortalCascade":
					ClearPortalCacheInternal(int.Parse(data), true, clearRuntime);
					break;
				case "Tab":
					ClearTabCacheInternal(int.Parse(data), clearRuntime);
					break;
			}
		}
		protected void RemoveInternal(string CacheKey)
		{
			DataCache.RemoveFromPrivateDictionary(CacheKey);
			if (Cache[CacheKey] != null) {
				Cache.Remove(CacheKey);
			}
		}
		public virtual void Clear(string type, string data)
		{
			ClearCacheInternal(type, data, false);
		}
		public virtual IDictionaryEnumerator GetEnumerator()
		{
			return Cache.GetEnumerator();
		}
		public virtual object GetItem(string CacheKey)
		{
			return Cache[CacheKey];
		}
		public virtual void Insert(string CacheKey, object objObject)
		{
			DNNCacheDependency objDependency = null;
			Insert(CacheKey, objObject, objDependency, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
		}
		public virtual void Insert(string CacheKey, object objObject, DNNCacheDependency objDependency)
		{
			Insert(CacheKey, objObject, objDependency, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
		}
		public virtual void Insert(string CacheKey, object objObject, DNNCacheDependency objDependency, System.DateTime AbsoluteExpiration, System.TimeSpan SlidingExpiration)
		{
			Insert(CacheKey, objObject, objDependency, AbsoluteExpiration, SlidingExpiration, CacheItemPriority.Default, null);
		}
		public virtual void Insert(string CacheKey, object Value, DNNCacheDependency objDependency, System.DateTime AbsoluteExpiration, System.TimeSpan SlidingExpiration, CacheItemPriority Priority, CacheItemRemovedCallback OnRemoveCallback)
		{
			if (objDependency == null) {
				Cache.Insert(CacheKey, Value, null, AbsoluteExpiration, SlidingExpiration, Priority, OnRemoveCallback);
			} else {
				Cache.Insert(CacheKey, Value, objDependency.SystemCacheDependency, AbsoluteExpiration, SlidingExpiration, Priority, OnRemoveCallback);
			}
		}
		public virtual bool IsWebFarm()
		{
			return (ServerController.GetEnabledServers().Count > 1);
		}
		public virtual string PurgeCache()
		{
			return Localization.Localization.GetString("PurgeCacheUnsupported.Text", Localization.Localization.GlobalResourceFile);
		}
		public virtual void Remove(string CacheKey)
		{
			RemoveInternal(CacheKey);
		}
	}
}
